package Olivia.olivia3d.model
{
	import flash.geom.Matrix3D;

	public class AnimationMat
	{
		public var orm:ORotationMat;
		public var tx:Number;
		public var ty:Number;
		public var tz:Number;
		
		public function AnimationMat(arr:Array=null)
		{
			orm = new ORotationMat(arr);
			if(arr){
				tx = arr[9];
				ty = arr[10];
				tz = arr[11];
			}
		}
		
		public function setupLocalToParent(rot:Array,pos:Array):void
		{
			var rotMatrix:ORotationMat = orm;
			rotMatrix.setup_right(rot);
			//rotMatrix表达的是父->局部的关系
			//我们要表达的是局部-->父亲的关系;所以要转置
			var arr:Array = [rotMatrix.m11,rotMatrix.m21,rotMatrix.m31,
				rotMatrix.m12,rotMatrix.m22,rotMatrix.m32,
				rotMatrix.m13,rotMatrix.m23,rotMatrix.m33];
			orm.Mat = arr;
			tx = pos[0];
			ty = pos[1];
			tz = pos[2];
		}
		
		public function setupParentToLocal(rot:Array,pos:Array):void
		{
			var rotMatrix:ORotationMat = orm;
			rotMatrix.setup_right(rot);
			//rotMatrix表达的是局部->父的关系
			var xtx:Number = -(pos[0]*rotMatrix.m11+pos[1]*rotMatrix.m21+pos[2]*rotMatrix.m31);
			var xty:Number = -(pos[0]*rotMatrix.m12+pos[1]*rotMatrix.m22+pos[2]*rotMatrix.m32);
			var xtz:Number = -(pos[0]*rotMatrix.m13+pos[1]*rotMatrix.m23+pos[2]*rotMatrix.m33);
			//value
			tx = xtx;
			ty = xty;
			tz = xtz;
		}
		
		public function get Mat():Array
		{
			var reMat:Array = orm.Mat;
			reMat.splice(3,0,tx);
			reMat.splice(7,0,ty);
			reMat.push(tz);
			return reMat;
		}
		
		public function get matrix_vec():Array{
			return [orm.m11,orm.m21,orm.m31, tx,orm.m12,orm.m22,orm.m32,ty,orm.m13,orm.m23,orm.m33,tz];
		}
		
		public static function inverse(m:AnimationMat):AnimationMat
		{
			var d:Number = m.det;
			if( Math.abs(d) < 0.001 )
			{
				// Determinant zero, there's no inverse
				return null;
			}
			
			var oneOverDet:Number = 1/d;
			var  r:AnimationMat=new AnimationMat();
			r.orm.m11 = (m.orm.m22*m.orm.m33 - m.orm.m23*m.orm.m32) * oneOverDet;
			r.orm.m12 = (m.orm.m13*m.orm.m32 - m.orm.m12*m.orm.m33) * oneOverDet;
			r.orm.m13 = (m.orm.m12*m.orm.m23 - m.orm.m13*m.orm.m22) * oneOverDet;
			r.orm.m21 = (m.orm.m23*m.orm.m31 - m.orm.m21*m.orm.m33) * oneOverDet;
			r.orm.m22 = (m.orm.m11*m.orm.m33 - m.orm.m13*m.orm.m31) * oneOverDet;
			r.orm.m23 = (m.orm.m13*m.orm.m21 - m.orm.m11*m.orm.m23) * oneOverDet;
			r.orm.m31 = (m.orm.m21*m.orm.m32 - m.orm.m22*m.orm.m31) * oneOverDet;
			r.orm.m32 = (m.orm.m12*m.orm.m31 - m.orm.m11*m.orm.m32) * oneOverDet;
			r.orm.m33 = (m.orm.m11*m.orm.m22 - m.orm.m12*m.orm.m21) * oneOverDet;
			// Compute the translation portion of the inverse
			r.tx = -(m.tx*r.orm.m11 + m.ty*r.orm.m21 + m.tz*r.orm.m31);
			r.ty = -(m.tx*r.orm.m12 + m.ty*r.orm.m22 + m.tz*r.orm.m32);
			r.tz = -(m.tx*r.orm.m13 + m.ty*r.orm.m23 + m.tz*r.orm.m33);
			// Return it. Ouch - involves a copy constructor call. If speed
			// is critical, we may need a seperate function which places the
			// result where we want it...
			return r;
		}
		
		public function get det():Number
		{
			var m:AnimationMat = this;
			return	m.orm.m11 * (m.orm.m22*m.orm.m33 - m.orm.m23*m.orm.m32)
				+ m.orm.m12 * (m.orm.m23*m.orm.m31 - m.orm.m21*m.orm.m33)
				+ m.orm.m13 * (m.orm.m21*m.orm.m32 - m.orm.m22*m.orm.m31);
		}
		
		public function append(am:AnimationMat):void
		{
			var arr:Array=[];
			//	m11	m12	m13
			arr[0] = orm.m11*am.orm.m11 + orm.m12*am.orm.m21+
				orm.m13*am.orm.m31;// + 0*am.tx;
			arr[1] = orm.m11*am.orm.m12 + orm.m12*am.orm.m22+
				orm.m13*am.orm.m32;// + 0*am.ty;
			arr[2] = orm.m11*am.orm.m13 + orm.m12*am.orm.m23+
				orm.m13*am.orm.m33;// + 0*am.tz;
			//	m21	m22	m23
			arr[3] = orm.m21*am.orm.m11 + orm.m22*am.orm.m21+
				orm.m23*am.orm.m31;// + 0*am.tx;
			arr[4] = orm.m21*am.orm.m12 + orm.m22*am.orm.m22+
				orm.m23*am.orm.m32;// + 0*am.ty;
			arr[5] = orm.m21*am.orm.m13 + orm.m22*am.orm.m23+
				orm.m23*am.orm.m33;// + 0*am.tz;
			//	m31	m32	m33
			arr[6] = orm.m31*am.orm.m11 + orm.m32*am.orm.m21+
				orm.m33*am.orm.m31;// + 0*am.tx;
			arr[7] = orm.m31*am.orm.m12 + orm.m32*am.orm.m22+
				orm.m33*am.orm.m32;// + 0*am.ty;
			arr[8] = orm.m31*am.orm.m13 + orm.m32*am.orm.m23+
				orm.m33*am.orm.m33;// + 0*am.tz;
			//	tx	ty	tz
			arr[9] = tx*am.orm.m11 + ty*am.orm.m21 +
				tz*am.orm.m31 + am.tx;
			arr[10] = tx*am.orm.m12 + ty*am.orm.m22 +
				tz*am.orm.m32 + am.ty;
			arr[11] = tx*am.orm.m13 + ty*am.orm.m23 +
				tz*am.orm.m33 + am.tz;
			//value
			orm = new ORotationMat(arr);
			tx = arr[9];
			ty = arr[10];
			tz = arr[11];
		}
		
		public function prepend(am:AnimationMat):void
		{
			var arr:Array=[];
			//	m11	m12	m13
			arr[0] = am.orm.m11*orm.m11 + am.orm.m12*orm.m21 +
				am.orm.m13*orm.m31;// + 0*tx;
			arr[1] = am.orm.m11*orm.m12 + am.orm.m12*orm.m22 +
				am.orm.m13*orm.m32;// + 0*ty;
			arr[2] = am.orm.m11*orm.m13 + am.orm.m12*orm.m23 + 
				am.orm.m13*orm.m33;// + 0*tz;
			//	m21	m22	m23
			arr[3] = am.orm.m21*orm.m11 + am.orm.m22*orm.m21 +
				am.orm.m23*orm.m31;
			arr[4] = am.orm.m21*orm.m12 + am.orm.m22*orm.m22 +
				am.orm.m23*orm.m32;
			arr[5] = am.orm.m21*orm.m13 + am.orm.m22*orm.m23 + 
				am.orm.m23*orm.m33;
			//	m31	m32	m33
			arr[6] = am.orm.m31*orm.m11 + am.orm.m32*orm.m21 +
				am.orm.m33*orm.m31;
			arr[7] = am.orm.m31*orm.m12 + am.orm.m32*orm.m22 +
				am.orm.m33*orm.m32;
			arr[8] = am.orm.m31*orm.m13 + am.orm.m32*orm.m23 + 
				am.orm.m33*orm.m33;
			//	tx	ty	tz
			arr[9] = am.tx*orm.m11 + am.ty*orm.m21 + 
				am.tz*orm.m31 + tx;
			arr[10] = am.tx*orm.m12 + am.ty*orm.m22 +
				am.tz*orm.m32 + ty;
			arr[11] = am.tx*orm.m13 + am.ty*orm.m23 +
				am.tz*orm.m33 + tz;
			//value
			orm = new ORotationMat(arr);
			tx = arr[9];
			ty = arr[10];
			tz = arr[11];
		}
		
		public function toString(): String
		{
			var s:String = "";
			
			s += int(orm.m11*1000)/1000 + "\t\t" + int(orm.m12*1000)/1000 + "\t\t" + int(orm.m13*1000)/1000 + "\t\t" + int(tx*1000)/1000 +"\n";
			s += int(orm.m21*1000)/1000 + "\t\t" + int(orm.m22*1000)/1000 + "\t\t" + int(orm.m23*1000)/1000 + "\t\t" + int(ty*1000)/1000 + "\n";
			s += int(orm.m31*1000)/1000 + "\t\t" + int(orm.m32*1000)/1000 + "\t\t" + int(orm.m33*1000)/1000 + "\t\t" + int(tz*1000)/1000 + "\n";
			
			return s;
		}
	}
}